package cn.remex.task;

import cn.remex.core.exception.ServiceCode;
import cn.remex.core.quartz.Job;
import cn.remex.core.quartz.SchedulerManager;
import cn.remex.core.quartz.Task;
import cn.remex.core.util.Assert;
import cn.remex.db.Database;
import cn.remex.db.sql.SqlColumn;
import cn.remex.task.model.SysMatter;
import cn.remex.task.model.SysTask;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.remex.db.sql.WhereRuleOper.*;
import static cn.remex.task.TaskConst.ProcessStatus.*;


/**
 * 名称：
 * 缩写：
 * 用途：
 * Created by yangy on 2016/12/24 0024.
 */
public abstract class TaskController implements TaskConst{
	private int maxJobCount = 100;
	private ProcessStatus curStatus;
	protected SysTask sysTask;
	protected Map<String, SysMatter> curSysMatters = new HashMap<>();//保存当前分析器的各个job的配置状态
	
	//quartz对象
	protected Map<String, Task> curMatterQuartzTask = new HashMap<>();//保存当前job实例
	protected Task curQuartzTask;

	public TaskController(SysTask SysTask) {
		this.sysTask = SysTask;
		this.curQuartzTask = createManagerDaemonTask();
		this.curQuartzTask.putJobParams("SysTask", this.sysTask);
	}

	//=======getter and setter=============//
	void setCurStatus(ProcessStatus curStatus) {
		this.curStatus = curStatus;
	}
	Task getCurQuartzTask() {
		return curQuartzTask;
	}
	void setCurQuartzTask(Task curQuartzTask) {
		this.curQuartzTask = curQuartzTask;
	}
	int getMaxJobCount() {
		return maxJobCount;
	}
	public Map<String, SysMatter> getCurMatters() {
		return curSysMatters;
	}
	public Map<String, Task> getCurMatterQuartzTask() {
		return curMatterQuartzTask;
	}
	public ProcessStatus getCurStatus() {
		return curStatus;
	}
	public SysTask getSysTask() {
		return sysTask;
	}

	//=============分析器必须重载的方法================//
	public abstract Task createManagerDaemonTask();
	public boolean bootCreditJob(SysMatter sysMatter) {
		logger.info("启动订单分析中的Job：id={}, type={}, status={}, param={}, result={}", sysMatter.getId(), sysMatter.getMatterType()
				, sysMatter.getProcessStatus(), sysMatter.getParams(), sysMatter.getResults());

		Database.update(SysMatter.class)
				.assignColumn(SysMatter::getProcessStatus, DOING)
				.assignColumn(SysMatter::getStartTime, new Date())
				.filterBy(SysMatter::getSysTask, equal, sysMatter.getSysTask())
				.filterBy(SysMatter::getMatterType, equal, sysMatter.getMatterType())
				.execute().assertEffectOneRow(ServiceCode.FAIL, "信审任务启动失败,可能该任务未配置，matterType=" + sysMatter.getMatterType());

		Class<? extends Job> jobClass = TaskCenter.obtainMatterJobClass(sysMatter.getSysTask().getTaskType(), sysMatter.getMatterType());
		Assert.notNull(jobClass, ServiceCode.FAIL, "订单分析的jobClass没有找到不能为空, matterType=" + sysMatter.getMatterType());
		Task subTask = new Task(jobClass)
				.suffIdentify(sysTask.key())
				.suffIdentify(sysMatter.getMatterType().toString())
				.triggerType(sysMatter.getTriggerType())
				.cronExpression(sysMatter.getCron())
				.startAt(sysMatter.getStartTime())
				.ignoreWhenExsite(true)
				.delayStart(0);

		subTask.putJobParams("sysMatter", sysMatter);
		curMatterQuartzTask.put(sysMatter.getMatterType(), subTask);
		curSysMatters.put(sysMatter.getMatterType(), sysMatter);
		SchedulerManager.getDefaultScheduler().addTask(subTask);
		return true;
	}
	public TaskController stopCreditJob(SysMatter jobConfig) {
		logger.info("移除订单分析中的Job：id={}, type={}, status={}, param={}, result={}", jobConfig.getId(), jobConfig.getMatterType()
				, jobConfig.getProcessStatus(), jobConfig.getParams(), jobConfig.getResults());

		Task subTask = curMatterQuartzTask.get(jobConfig.getMatterType());
		curSysMatters.remove(jobConfig.getMatterType());//任务完成，更新状态
		curMatterQuartzTask.remove(jobConfig.getMatterType());
		if (null != subTask) {
			SchedulerManager.getDefaultScheduler().deleteTask(subTask);
			logger.info("移除Job时task为null, relationId={}, matterType={}, jobParam={}", jobConfig.getSysTask().getRelationId(), jobConfig.getMatterType(), jobConfig.getParams());
		}
		return this;
	}
	public TaskController checkAndRemoveCreditJob() {
		for (Object jobConfigObj: curSysMatters.values().toArray()){
			SysMatter jobConfig = (SysMatter) jobConfigObj;
			ProcessStatus jobStatus = jobConfig.getProcessStatus();
			// 失败或完成或错误或等待中需要移除
			// 不在quartz队列中的需要删除
			if (FAIL.equals(jobStatus) || WAITING.equals(jobStatus) || FINISH.equals(jobStatus) || ERROR.equals(jobStatus)
					|| !SchedulerManager.getDefaultScheduler().checkExists(curMatterQuartzTask.get(jobConfig.getMatterType()))
					) {
				logger.info("移除Job, relationId={}, matterType={}, jobParam={}", sysTask.getRelationId(), jobConfig.getMatterType(), jobConfig.getParams());
				stopCreditJob(jobConfig);
			}
		}
		return this;
	}
	public TaskController checkAndBootCreditJob() {
		List<SysMatter> preparedAnalyzers = Database.select(SysMatter.class)
				.withModel(SysMatter::getSysTask, SqlColumn::withBase)
				.filterBy(SysMatter::getSysTask, equal, sysTask)
				.filterBy(SysMatter::getProcessStatus, in, NEW,  TODO, DOING) //WAITING WAITING不能启动 LHY  //FAIL, LHY LXT 失败的暂时不要调用，容易循环
				.rowCount(100).execute().obtainObjects(SysMatter.class);
		for (SysMatter creditJobConfig : preparedAnalyzers) {
			Task curJobTask = curMatterQuartzTask.get(creditJobConfig.getMatterType());
			//如果已经在运行列表中且已经运行了，则不用启动
			if(null!=curJobTask && SchedulerManager.getDefaultScheduler().checkExists(curJobTask)){
				continue;
			}

			if (curSysMatters.size() < getMaxJobCount()) {
				bootCreditJob(creditJobConfig);
			}
		}
		return this;
	}
	public TaskController boot(){
		SchedulerManager.getDefaultScheduler().addTask(curQuartzTask);
		return this;
	}
	//=============分析器静态共用方法================//
	public static void handleAnalysisNotice(SysTask anaConfig, String jobType, String jobParams){
		//对应的jobType 需要存在，否则不执行该job
		Database.update(SysMatter.class)
				.assignColumn(SysMatter::getProcessStatus, TODO)//把对应的任务激活
				.assignColumn(SysMatter::getParams, jobParams)
				.filterBy(SysMatter::getSysTask, equal, anaConfig.getId())
				.filterBy(SysMatter::getMatterType, equal, jobType)
				.execute().assertEffectOneRow(ServiceCode.FAIL, "更新job状态失败, type=" + jobType + ", jobParams=" + jobParams);

		Database.update(SysTask.class)
				.filterById(anaConfig.getId())
				.filterBy(SysTask::getProcessStatus, notIn, DOING)
				.assignColumn(SysTask::getProcessStatus, TODO)
				.execute().assertTrue(rvo -> rvo.getRecordCount() <= 1, ServiceCode.FAIL, "接到分析通知，处理状态失败，matterType=");

	}

	public abstract void updateParams(String analyzerJobParams);
}
